package utils

import (
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/base64"
	"encoding/hex"
	"encoding/pem"
	"errors"
	"os"
)

// 生成RSA私钥和公钥，保存到文件中
// bits 证书大小
func GenerateRSAKey(privatePath, publicPath string, bits ...int) error {
	bitGen := 2048
	if len(bits) > 0 {
		bitGen = bits[0]
	}
	//GenerateKey函数使用随机数据生成器random生成一对具有指定字位数的RSA密钥
	//Reader是一个全局、共享的密码用强随机数生成器
	privateKey, err := rsa.GenerateKey(rand.Reader, bitGen)
	if err != nil {
		return err
	}
	//保存私钥
	//通过x509标准将得到的ras私钥序列化为ASN.1 的 DER编码字符串
	X509PrivateKey := x509.MarshalPKCS1PrivateKey(privateKey)
	//使用pem格式对x509输出的内容进行编码
	//创建文件保存私钥
	//privateFile, err := os.Create("private.pem")
	privateFile, err := os.Create(privatePath)
	if err != nil {
		return err
	}
	defer privateFile.Close()
	//构建一个pem.Block结构体对象
	privateBlock := pem.Block{Type: "RSA Private Key", Bytes: X509PrivateKey}
	//将数据保存到文件
	err = pem.Encode(privateFile, &privateBlock)
	if err != nil {
		return err
	}

	//保存公钥
	//获取公钥的数据
	publicKey := privateKey.PublicKey
	//X509对公钥编码
	X509PublicKey, err := x509.MarshalPKIXPublicKey(&publicKey)
	if err != nil {
		return err
	}
	//pem格式编码
	//创建用于保存公钥的文件
	//publicFile, err := os.Create("public.pem")
	publicFile, err := os.Create(publicPath)
	if err != nil {
		return err
	}
	defer publicFile.Close()
	//创建一个pem.Block结构体对象
	publicBlock := pem.Block{Type: "RSA Public Key", Bytes: X509PublicKey}
	//保存到文件
	err = pem.Encode(publicFile, &publicBlock)
	if err != nil {
		return err
	}
	return nil
}

// RSA原始加密
// plainText 要加密的数据
// path 公钥匙文件地址
func RSAEncryptByFile(plainText []byte, path string) ([]byte, error) {
	//打开文件
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer file.Close()
	//读取文件的内容
	info, err := file.Stat()
	if err != nil {
		return nil, err
	}
	buf := make([]byte, info.Size())
	_, err = file.Read(buf)
	if err != nil {
		return nil, err
	}
	//pem解码
	block, _ := pem.Decode(buf)
	//x509解码

	publicKeyInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return nil, err
	}
	//类型断言
	publicKey := publicKeyInterface.(*rsa.PublicKey)
	//对明文进行加密
	cipherText, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, plainText)
	if err != nil {
		return nil, err
	}
	//返回密文
	return cipherText, nil
}

// RSA解密
// cipherText 需要解密的byte数据
// path 私钥文件路径
func RSADecryptByFile(cipherText []byte, path string) ([]byte, error) {
	//打开文件
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer file.Close()
	//获取文件内容
	info, _ := file.Stat()
	buf := make([]byte, info.Size())
	_, err = file.Read(buf)
	if err != nil {
		return nil, err
	}
	//pem解码
	block, _ := pem.Decode(buf)
	//X509解码
	privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil {
		return nil, err
	}
	//对密文进行解密
	//rsa.SignPKCS1v15(rand.Reader,privateKey,crypto.SHA256,cipherText)
	plainText, err := rsa.DecryptPKCS1v15(rand.Reader, privateKey, cipherText)
	//返回明文
	return plainText, err
}

func RSAEncrypt(plainText string, publicKeyStr string) (string, error) {
	//pem解码
	buf := []byte(publicKeyStr)
	block, _ := pem.Decode(buf)
	//x509解码
	publicKeyInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return "", err
	}
	//类型断言
	publicKey := publicKeyInterface.(*rsa.PublicKey)
	//对明文进行加密
	cipherText, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, []byte(plainText))
	//rsa.SignPKCS1v15(rand.Reader,privateKey,crypto.SHA256,cipherText)
	if err != nil {
		return "", err
	}
	//返回密文
	return base64.StdEncoding.EncodeToString(cipherText), nil
}

func RSADecrypt(cipherTextStr string, privateKeyStr string) (string, error) {
	//pem解码
	buf := []byte(privateKeyStr)
	block, _ := pem.Decode(buf)
	//X509解码
	privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil {
		return "", err
	}
	cipherText, err := base64.StdEncoding.DecodeString(cipherTextStr)
	if err != nil {
		return "", err
	}
	//对密文进行解密
	plainText, err := rsa.DecryptPKCS1v15(rand.Reader, privateKey, cipherText)
	//返回明文
	if err != nil {
		return "", err
	}
	return string(plainText), nil
}

// rsa签名
func RSASign(plainText string, privateKeyStr string) (string, error) {
	if plainText == "" || privateKeyStr == "" {
		return "", errors.New("plain text and private key can not be empty")
	}
	hashed := Sha256(plainText)
	//pem解码
	buf := []byte(privateKeyStr)
	block, _ := pem.Decode(buf)
	if block == nil {
		return "", errors.New("key decode fail")
	}
	//X509解码
	privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil {
		return "", err
	}
	//对密文进行加签
	cipherText, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, hashed)
	if err != nil {
		return "", err
	}
	//return base64.StdEncoding.EncodeToString(cipherText),nil
	return hex.EncodeToString(cipherText), nil
}

// rsa认证
func RSAVerify(plainText, signText string, publicKeyStr string) bool {
	if plainText == "" || signText == "" {
		return false
	}
	hashed := Sha256(plainText)
	//pem解码
	buf := []byte(publicKeyStr)
	block, _ := pem.Decode(buf)
	if block == nil {
		return false
	}
	//x509解码
	publicKeyInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return false
	}
	//类型断言
	publicKey := publicKeyInterface.(*rsa.PublicKey)

	//signTextByte,err := base64.StdEncoding.DecodeString(signText)
	signTextByte, err := hex.DecodeString(signText)
	if err != nil {
		return false
	}
	//对明文进行加密
	err = rsa.VerifyPKCS1v15(publicKey, crypto.SHA256, hashed, signTextByte)
	if err != nil {
		return false
	}
	return true
}
